#pragma once

#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/socket.h>
#include <jsoncpp/json/json.h>

// 自己定制协议（特殊符号）：分隔符、换行符
#define SEP " "
#define SEP_LEN strlen(SEP) // 不能使用sizeof()
#define LINE_SEP "\r\n"
#define LINE_SEP_LEN strlen(LINE_SEP) // 不能使用sizeof()

enum
{
    OK = 0,
    DIV_ZERO,
    MOD_ZERO,
    OP_ERROR
};

//"_exitcode result" --> "content_len\r\n_exitcode result\r\n"
//"_x _op _y" --> "content_len\r\n_x _op _y\r\n"
std::string enLength(const std::string &text) // 添加协议规则，用于构建一个完整的报文（类似"打包"）
{
    std::string send_string = std::to_string(text.size()); // 用于计算有效载荷的长度"_x _op _y"
    send_string += LINE_SEP;
    send_string += text;
    send_string += LINE_SEP;
    return send_string;
}

bool deLength(const std::string &package, std::string *text) // 获取报文中的有效载荷（类似"解包"）
{
    auto pos = package.find(LINE_SEP);
    if (pos == std::string::npos)
    {
        std::cout << "deLength return false" << std::endl;

        return false;
    }
    int textLen = std::stoi(package.substr(0, pos)); // 计算有效载荷的长度
    *text = package.substr(pos + LINE_SEP_LEN, textLen);
    std::cout << "deLength return true" << std::endl;
    return true;
}

class Request // 请求类
{
public:
    int _x;
    char _op;
    int _y;

public:
    Request(int x, int y, char op)
        : _x(x), _y(y), _op(op)
    {
    }
    Request()
        : _x(0), _y(0), _op(0)
    {
    }
    bool serialize(std::string *out) // 序列化，将成员变量转字符串序列
    {
#ifdef MYSELF
        // 结构化对象 --> 序列化的字符串"_x _op _y"
        (*out).clear();
        std::string x_str = std::to_string(_x);
        std::string y_str = std::to_string(_y);
        *out = x_str + SEP + _op + SEP + y_str; // 加上分隔符
#else
        // 使用json序列化
        /*
        Cal: 1+1
        计算式：1+1
        使用json序列化
        send_str: 31
        {"first":1,"op":43,"second":1}

        */
        std::cout << "使用json序列化" << std::endl;
        Json::Value root; // 万能对象
        root["first"] = _x;
        root["second"] = _y;
        root["op"] = _op;

        Json::FastWriter writer;
        // Json::StyledWriter writer;
        *out = writer.write(root);

#endif
        return true;
    }
    bool deserialize(const std::string &in) // 反序列化
    {
#ifdef MYSELF
        // 序列化的字符串"_x _op _y" --> 结构化对象
        // 找第一个SEP和第二个SEP
        auto leftSpace = in.find(SEP);
        auto rightSpace = in.rfind(SEP);
        // 合法判断
        if (leftSpace == rightSpace || leftSpace == std::string::npos || rightSpace == std::string::npos)
            return false;
        // 子串提取
        std::string x_str = in.substr(0, leftSpace);

        // std::string in = "1##%##2";// in.rfind("##")返回的是4，左边#的位置
        // _op长度 = rightSpace - leftSpace - SEP_LEN
        if (rightSpace - leftSpace - SEP_LEN != 1) // 表示操作符一定只占1位
        {
            return false;
        }
        _op = in.substr(leftSpace + SEP_LEN, 1)[0];
        std::string y_str = in.substr(rightSpace + SEP_LEN);
        // 对x，y进行转换
        _x = std::stoi(x_str);
        _y = std::stoi(y_str);
#else
        // 使用json反序列化
        Json::Value root;
        Json::Reader reader;
        reader.parse(in, root); // 参数1：解析哪个字符串 参数2：解析到哪个对象中

        _x = root["first"].asInt();
        _y = root["second"].asInt();
        _op = root["op"].asInt();

#endif
        return true;
    }
    ~Request() {}
};

class Response // 响应类
{
public:
    int _exitCode; // 0代表计算成功，非0代表错误
    int _result;   // 结果

public:
    Response() {}

    bool serialize(std::string *out) // 序列化，将成员变量转字符串
    {
        *out = "";
        *out = std::to_string(_exitCode) + SEP + std::to_string(_result);
        return true;
    }
    bool deserialize(const std::string &in) // 反序列化
    {
        auto space = in.find(SEP); // 找空格
        if (space == std::string::npos)
            return false;
        std::string exitString = in.substr(0, space);
        std::string resString = in.substr(space + SEP_LEN);
        // 一个字符串为空就false
        if (exitString.empty() || resString.empty())
            return false;

        _exitCode = std::stoi(exitString);
        _result = std::stoi(resString);
        return true;
    }

    ~Response() {}
};

bool recvPackage(int sock, std::string &inbuffer, std::string *text) // 服务器、客户端读取一个完整报文
{
    // 将缓冲区中的数据拆分（组成）为一个完整报文"content_len\r\n_x _op _y\r\n"
    char buffer[1024];
    while (1)
    {
        // read/write通用，recv/send TCP recvfrom/sendto UDP
        ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0); // 第四个参数0，阻塞式读取，相当于read
        if (n > 0)
        {
            buffer[n] = 0; // 加\0
            inbuffer += buffer;

            // 检查有没有读到一个完整报文
            // TCP是面向字节流的，不关心有没有读到一个完整报文
            // 是否读到一个完整报文需要上层关心
            auto pos = inbuffer.find(LINE_SEP);
            if (pos == std::string::npos) // 没有\r\n，continue，等下次读取
                continue;
            std::string textLen_str = inbuffer.substr(0, pos);
            int textLen = std::stoi(textLen_str);
            // size()返回的是无\0的长度
            int totalLen = textLen_str.size() + textLen + 2 * LINE_SEP_LEN;
            if (inbuffer.size() < totalLen) // 没读到一个完整报文，等下次读取
            {
                std::cout << "你输入的消息，没有严格遵守我们的协议，正在等待后续的内容, continue" << std::endl;
                continue;
            }
            std::cout << "取报文前inbuffer中的内容:\n"
                      << inbuffer << std::endl;

            // 走到这里，一定有一个完整的报文
            *text = inbuffer.substr(0, totalLen); // 取出一个报文
            inbuffer.erase(0, totalLen);          // 删掉缓冲区中刚刚被提取走的报文数据
            std::cout << "取报文后inbuffer中的内容:\n"
                      << inbuffer << std::endl;
            break; // 拿到一个完整报文就退出
        }
        else
        {
            return false;
        }
    }
    std::cout << "recvPackage return " << std::endl;
    return true;
}

void recvPackageAll(int sock, std::string &inbuffer, std::vector<std::string> *out)
{
    std::string line;
    // 拿到sock的所有报文放到out中，可以由外部一次处理
    while (recvPackage(sock, inbuffer, &line))
    {
        out->push_back(line);
    }
}
